-- $Name: Project B$
-- $Version: 0.4$
instead_version "1.3.3";

require 'hideinv';
require 'prefs';
require 'xact';

function init()
	nextbl();
	cr_block();
	draw_block();
	take(n_block);
--	take(coord);
	take(point);
	take(level);
end;

prefs.hs = {};

global {
	fade = false;
	block = {};
	nx_block = {};
	pnt = 0;
	lev = 1;
}

-- комната с игровым полем
main = room {
	fading = function ()
		if fade == false then
			return false;
		else
			return true, 2;
		end;
	end;
	forcedsc = true;
	nam = 'Project B';
	disp = '';
	dsc = function()
		local outp = '';
		for y=1,22,1 do
			for x=1,12,1 do
				outp = outp..img(call(field_par,field[y][x]));
			end;
		outp = outp..'^';
		end;
		return txtc(outp);
	end;
};

-- создание новой фигуры сверху поля
function cr_block()
	if lev < 10 then timer:set(999-(100*lev)); end;
	block.gr = {};
	block._x = 4;
	block._y = 1;
	block.gr = deepcopy(nx_block);
	nextbl();
end;

function nextbl()
	local bl = rnd(7);
	nx_block = deepcopy(block_tab[bl]);
end;

-- отрисовка фигуры на поле
function draw_block()
	for y=1,#block.gr,1 do
		for x=1,#block.gr[1],1 do
			if block.gr[y][x] == 1 then
				field[block._y+y-1][block._x+x-1] = 1;
			end;
		end;
	end;
end;

-- удаление фигуры с поля
function clear_block()
	for y=1,#block.gr,1 do
		for x=1,#block.gr[1],1 do
			if block.gr[y][x] == 1 then
				field[block._y+y-1][block._x+x-1] = 0;
			end;
		end;
	end;
end;

-- сдвиг фигуры
function move_bl(mx,my)
	fade = false;
	if coll(mx,my) == 0 then
		clear_block();
		block._y = block._y + my;
		block._x = block._x + mx;
		draw_block();
	elseif coll(mx,my) == 1 then return;
	elseif coll(mx,my) == 2 then
		set_sound('snd/drop.wav');
		cr_block();
		line();
		if coll(0,0,1) ~= 0 then timer:stop(); set_sound('snd/theend.wav'); hisc(); goto(loose); end;
		draw_block();
		return;
	end;
end;

-- проверка на столкновения
function coll(cx,cy,z,r)
	local t_field = deepcopy(field);
	local t_block = deepcopy(block);
if z~=1 then
	for y=1,#t_block.gr,1 do
		for x=1,#t_block.gr[1],1 do
			if t_block.gr[y][x] == 1 then
				t_field[t_block._y+y-1][t_block._x+x-1] = 0;
			end;
		end;
	end;
end;
if r==1 then t_block.gr = rotate(t_block.gr); end;
-- вычисление следующего шага
	for y=1,#t_block.gr,1 do
		for x=1,#t_block.gr[1],1 do
			if t_block.gr[y][x] == 1 then
				t_field[t_block._y+y-1+cy][t_block._x+x-1+cx] = t_field[t_block._y+y-1+cy][t_block._x+x-1+cx] + 1;
			end;
		end;
	end;
-- проверка наложения с рамкой поля
	for y=1,22,1 do
		for x=1,12,1 do
			if cy > 0 and t_field[y][x] > 2 then return 2;
			elseif t_field[y][x] > 2 then return 1;
			end;
		end;
	end;
-- проверка наложения с блоками
	for y=2,21,1 do
		for x=2,11,1 do
			if cy > 0 and t_field[y][x] > 1 then return 2;
			elseif t_field[y][x] > 1 then return 1;
			end;
		end;
	end;
	return 0;
end;

-- удаление заполненной линии
function line()
	local k;
	mod = 0;
	for y=2,21,1 do
		k = 0;
		for x=2,11,1 do
			if field[y][x] == 1 then k = k + 1; end;
		end;
		if k == 10 then
			fade = true;
			set_sound('snd/line.wav')
			field[y] = {2,0,0,0,0,0,0,0,0,0,0,2};
			mod = mod + 1;
			for cy=y,3,-1 do
				field[cy] = deepcopy(field[cy-1]);
			end;
		end;
	end;
	if mod == 1 then pnt = pnt + 100;
	elseif mod == 2 then pnt = pnt + 300;
	elseif mod == 3 then pnt = pnt + 700;
	elseif mod == 4 then pnt = pnt + 1500;
	end;
	ch_lvl();
end;

-- параметры смены уровня сложности
function ch_lvl()
	if pnt >= 1000 and pnt < 2000 then lev=2;
	elseif pnt >= 2000 and pnt < 3000 then lev=3;
	elseif pnt >= 3000 and pnt < 4000 then lev=4;
	elseif pnt >= 4000 and pnt < 5000 then lev=5;
	elseif pnt >= 5000 and pnt < 6000 then lev=6;
	elseif pnt >= 6000 and pnt < 7000 then lev=7;
	elseif pnt >= 7000 and pnt < 8000 then lev=8;
	elseif pnt >= 8000 then lev=9;
	end;
end;

-- поворот фигуры
function rotate(a)
	local b = {
		{0,0,0,0};
		{0,0,0,0};
		{0,0,0,0};
		{0,0,0,0};
	};
	local h = #a;
	local w = #a[1];
	local x, y;
	for x=1, w do
		b[w-x+1] = {0,0,0,0};
		for y=1, h do
			b[w-x+1][y] = a[y][x];
		end
	end
	return b;
end;

-- перехватчик клавиатуры
input.key = function(s,pr,key)
if here() == main then
	if not pr or key == 'escape' then return
	elseif key == 'right' then move_bl(1,0);
	elseif key == 'left' then move_bl(-1,0);
	elseif key == 'down' then move_bl(0,1);
	elseif key == 'up' then
		clear_block();
		if coll(0,0,0,1)==0 then
			block.gr = rotate(block.gr);
		end;
		draw_block();
	elseif key == 'space' then fall();
	end;
	return 'look';
end;
end;

-- падение фигуры при нажатии пробела
function fall()
	timer:set(-1);
end;

-- таймер?
timer.callback = function(s)
	move_bl(0,1);
	return 'look';
end;

-- массив возможных фигур
block_tab = {
	[1] = {
		{0,0,0,0};
		{0,1,1,0};
		{0,1,1,0};
		{0,0,0,0};
	};
	[2] = {
		{0,0,0,0};
		{1,1,1,1};
		{0,0,0,0};
		{0,0,0,0};
	};
	[3] = {
		{0,0,0,0};
		{0,0,1,1};
		{0,1,1,0};
		{0,0,0,0};
	};
	[4] = {
		{0,0,0,0};
		{0,1,1,0};
		{0,0,1,1};
		{0,0,0,0};
	};
	[5] = {
		{0,0,0,0};
		{0,1,1,1};
		{0,1,0,0};
		{0,0,0,0};
	};
	[6] = {
		{0,0,0,0};
		{0,1,1,1};
		{0,0,0,1};
		{0,0,0,0};
	};
	[7] = {
		{0,0,0,0};
		{0,1,1,1};
		{0,0,1,0};
		{0,0,0,0};
	};
};

-- массив игрового поля
global {
field = {
	{2,2,2,2,2,2,2,2,2,2,2,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,0,0,0,0,0,0,0,0,0,0,2};
	{2,2,2,2,2,2,2,2,2,2,2,2};
};
};

-- сслыки на изображения
field_par = {
	[0] = 'images/blank.png';
	[1] = 'images/block.png';
	[2] = 'images/border.png';
};

-- отображение следующего блока
n_block = stat {
	nam = function()
		local outp = '';
		for y=1,4,1 do
			for x=1,#nx_block[1],1 do
				if y <= #nx_block then outp = outp..img(call(field_par,nx_block[y][x]));
				else outp = outp..img(call(field_par,0));
				end;
			end;
			outp = outp..'^';
		end;
		return txtc(outp);
	end;
};

-- отображение игровых очков
point = stat {
	nam = function()
		return txtc('points: '..pnt); --txtc для более верного выравнивания
	end;
};

-- отображение уровня
level = stat {
	nam = function()
		return txtc('level: '..lev);  	--аналогично
	end;
};

-- комната конца игры
loose = xroom {
	hideinv = true;
	forsedsc = true;
	nam = 'end';
	disp = '';
	dsc = function() return txtc('^^^Конец игры!^^Вы набрали '..pnt..' очков^^Hi scores:^^'..highs()); end;
	xdsc = txtc('{сброс|Сбросить очки}');
	obj = {
		xact('сброс',code[[prefs.hs = {};goto(loose);]]);
	};
};

-- отображение таблицы рекордов
function highs()
	hs = '';
	for x=1,#prefs.hs,1 do
		hs = hs..x..'. '..tostring(prefs.hs[x])..'^';
	end;
	return hs;
end;

-- таблица рекордов
function hisc()
		if #prefs.hs > 9 then table.remove(prefs.hs); end;
		if pnt > 0 then table.insert(prefs.hs,pnt); end;
		table.sort(prefs.hs,function(a,b) return a>b; end)
		prefs:store();
end;

-- ф-ия копирующая таблицу
function deepcopy(object)
    local lookup_table = {}
    local function _copy(object)
        if type(object) ~= "table" then
            return object
        elseif lookup_table[object] then
            return lookup_table[object]
        end
        local new_table = {}
        lookup_table[object] = new_table
        for index, value in pairs(object) do
            new_table[_copy(index)] = _copy(value)
        end
        return setmetatable(new_table, getmetatable(object))
    end
    return _copy(object)
end;
